package com.jiamingZhao.mapper.factory;

import cn.hutool.core.util.StrUtil;
import com.jiamingZhao.sessoin.SqlSession;
import com.jiamingZhao.utils.DbUtil;
import com.jiamingZhao.wrapper.LambdaQueryWrapper;
import com.jiamingZhao.wrapper.Wrapper;
import com.jiamingZhao.wrapper.Wrappers;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * Mapper代理实现
 */
public class MapperProxy<T> implements InvocationHandler {
    private final SqlSession sqlSession;
    private final Class<T> mapperInterface;

    private final Class<T> clazz;
    
    public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface) {
        this.sqlSession = sqlSession;
        this.mapperInterface = mapperInterface;
        clazz = (Class<T>) DbUtil.getMapperEntityType(mapperInterface);
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            // 处理Object方法
            if (Object.class.equals(method.getDeclaringClass())) {
                return method.invoke(this, args);
            }
            
            // 处理默认方法（Java 8+）
            if (method.isDefault()) {
                return invokeDefaultMethod(proxy, method, args);
            }
            
            // 普通Mapper方法调用
            return execute(method, args);
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }
    
    private Object execute(Method method, Object[] args) {

        if ("list".equals(method.getName()) && Objects.isNull(args)) {
            return sqlSession.selectList(Wrappers.lambdaQuery(clazz));
        }

        //有参构造
        if ("list".equals(method.getName())) {
            @SuppressWarnings("unchecked")
            List<T> list = sqlSession.selectList((Wrapper<T>) args[0]);
            return list;
        }


        // 特殊处理getById方法
        if ("getById".equals(method.getName())) {
            LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery(clazz).apply(StrUtil.format("and id = {}", args[0]));
            return sqlSession.selectOne(wrapper);
        }
        
        // 其他方法处理...
        throw new RuntimeException("Method " + method.getName() + " not implemented");
    }
    
    private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
        @SuppressWarnings("JavaReflectionMemberAccess")
        Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
            .getDeclaredConstructor(Class.class, int.class);
        constructor.setAccessible(true);
        
        final Class<?> declaringClass = method.getDeclaringClass();
        return constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
            .unreflectSpecial(method, declaringClass)
            .bindTo(proxy)
            .invokeWithArguments(args);
    }
}